{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cython：Cython 基础，将源代码转换成扩展模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cython 基础"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前使用了手动的方法对 `C` 程序进行编译，而 `Cython` 则简化了这个过程。\n",
    "\n",
    "考虑之前的斐波拉契数列，`Python` 版本：\n",
    "\n",
    "```python\n",
    "def fib(n):\n",
    "    a,b = 1,1\n",
    "    for i in range(n):\n",
    "        a,b = a+b, a\n",
    "    return a\n",
    "```\n",
    "\n",
    "`C` 版本：\n",
    "\n",
    "```cpp\n",
    "int fib(int n) {\n",
    "    int tmp, i, a, b;\n",
    "    a = b = 1;\n",
    "    for (i=0; i<n; i++) {\n",
    "        tmp = a; a += b; b = tmp;\n",
    "    }\n",
    "    return a;\n",
    "}\n",
    "```\n",
    "\n",
    "`Cython` 版本：\n",
    "\n",
    "```cython\n",
    "def fib(int n):\n",
    "    cdef int i, a, b\n",
    "    a,b = 1,1\n",
    "    for i in range(n):\n",
    "        a,b = a+b, a\n",
    "    return a\n",
    "```\n",
    "\n",
    "这里 `cdef` 定义了 `C` 变量的类型。 \n",
    "\n",
    "**Cython** 的好处在于，我们使用了 **Python** 的语法，又有 **C/C++** 的效率，同时省去了之前直接编译成扩展模块的麻烦，并且提供了原生的 **Numpy** 支持。\n",
    "\n",
    "官方网址：http://www.cython.org\n",
    "\n",
    "其主要用法有两点：\n",
    "\n",
    "- 将 Python 程序转化为 C 程序\n",
    "- 包装 C/C++ 程序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 将源代码转换成扩展模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ipython 中使用 Cython 命令"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入 `Cython` `magic` 命令："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 `magic` 命令执行 `Cython`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%%cython\n",
    "def cyfib(int n):\n",
    "    cdef int i, a, b\n",
    "    a,b = 1,1\n",
    "    for i in range(n):\n",
    "        a,b = a+b, a\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "144"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cyfib(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 distutils 编译 Cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Cython` 代码以 `.pyx` 结尾，先通过 cython 转化为 `.c` 文件，再用 `gcc` 转化为 `.so(.pyd)` 文件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing fib.pyx\n"
     ]
    }
   ],
   "source": [
    "%%file fib.pyx\n",
    "def cyfib(int n):\n",
    "    cdef int i, a, b\n",
    "    a,b = 1,1\n",
    "    for i in range(n):\n",
    "        a,b = a+b, a\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting setup.py\n"
     ]
    }
   ],
   "source": [
    "%%file setup.py\n",
    "from distutils.core import setup\n",
    "from distutils.extension import Extension\n",
    "from Cython.Distutils import build_ext\n",
    "\n",
    "ext = Extension(\"fib\", sources=[\"fib.pyx\"])\n",
    "\n",
    "setup(ext_modules=[ext], cmdclass={'build_ext': build_ext})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编译成功："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "running build_ext\n",
      "cythoning fib.pyx to fib.c\n",
      "building 'fib' extension\n",
      "creating build\n",
      "creating build\\temp.win-amd64-2.7\n",
      "creating build\\temp.win-amd64-2.7\\Release\n",
      "C:\\Miniconda\\Scripts\\gcc.bat -DMS_WIN64 -mdll -O -Wall -IC:\\Miniconda\\include -IC:\\Miniconda\\PC -c fib.c -o build\\temp.win-amd64-2.7\\Release\\fib.o\n",
      "writing build\\temp.win-amd64-2.7\\Release\\fib.def\n",
      "C:\\Miniconda\\Scripts\\gcc.bat -DMS_WIN64 -shared -s build\\temp.win-amd64-2.7\\Release\\fib.o build\\temp.win-amd64-2.7\\Release\\fib.def -LC:\\Miniconda\\libs -LC:\\Miniconda\\PCbuild\\amd64 -lpython27 -lmsvcr90 -o \"C:\\Users\\Jin\\Documents\\Git\\python-tutorial\\07. interfacing with other languages\\fib.pyd\"\n"
     ]
    }
   ],
   "source": [
    "!python setup.py build_ext --inplace"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "144"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import fib\n",
    "\n",
    "fib.cyfib(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import zipfile\n",
    "\n",
    "f = zipfile.ZipFile('07-03-fib.zip','w',zipfile.ZIP_DEFLATED)\n",
    "\n",
    "names = 'fib.pyd fib.pyx fib.c setup.py'.split()\n",
    "for name in names:\n",
    "    f.write(name)\n",
    "\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 pyximport"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "清理之前生成的文件："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "!rm -f fib.pyd\n",
    "!rm -f fib.pyc\n",
    "!rm -f fib.C"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "清理之前导入的模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%reset -f"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 `pyximport`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "144"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pyximport\n",
    "pyximport.install()\n",
    "\n",
    "import fib\n",
    "\n",
    "fib.cyfib(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`install` 函数会自动检测 Cython 程序的变化，并自动导入，不过一般用于简单文件的编译。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "清理生成的文件："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "!rm -f setup*.*\n",
    "!rm -f fib.*\n",
    "!rm -rf build"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
